package com.hxbd.test.handles;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import com.hxbd.test.utils.IRedis;

public class GetAllClassByInterfaceOrSuperClass {
	@SuppressWarnings({ "rawtypes", "unchecked" })
    public static ArrayList<Class> getAllClassByInterface(Class clazz) {
        ArrayList<Class> list = new ArrayList<>();
        // 判断是否是一个接口
        if (clazz.isInterface()) {
            try {
                ArrayList<Class> allClass = getAllClass("");
                /**
                 * 循环判断路径下的所有类是否实现了指定的接口 并且排除接口类自己
                 */
                for (int i = 0; i < allClass.size(); i++) {
                    /**
                     * 判断是不是同一个接口
                     */
                    // isAssignableFrom:判定此 Class 对象所表示的类或接口与指定的 Class
                    // 参数所表示的类或接口是否相同，或是否是其超类或超接口
                    if (clazz.isAssignableFrom(allClass.get(i))) {
                        if (!clazz.equals(allClass.get(i))) {
                            // 自身并不加进去
                            list.add(allClass.get(i));
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println("出现异常");
            }
        } 
        return list;
    }
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static ArrayList<Class> getAllChildClassByInterface(Class clazz, Class sysCls) {
		ArrayList<Class> a1= getAllClassByInterface(clazz);
		a1.add(sysCls);
		ArrayList<Class> a2 = new ArrayList<>();
		for (int i = 0; i < a1.size(); i++) {
			Class c = a1.get(i);
			ArrayList<Class> a3 = new ArrayList<>();
			a3.addAll(a1);
			a3.remove(i);
			for (Class cc : a3) {
				if(c.isAssignableFrom(cc)) {
					a2.add(cc);
				}
			}			
		}
		a1.removeAll(a2);
		return a1;
    }
	@SuppressWarnings({ "rawtypes", "unchecked" })
    public static ArrayList<Class> getAllClassByInterfaceOrSuperClass(Class clazz) {
        ArrayList<Class> list = new ArrayList<>();
        // 判断是否是一个接口
        if (clazz.isInterface()) {
            try {
                ArrayList<Class> allClass = getAllClass("");
                /**
                 * 循环判断路径下的所有类是否实现了指定的接口 并且排除接口类自己
                 */
                for (int i = 0; i < allClass.size(); i++) {
                    /**
                     * 判断是不是同一个接口
                     */
                    // isAssignableFrom:判定此 Class 对象所表示的类或接口与指定的 Class
                    // 参数所表示的类或接口是否相同，或是否是其超类或超接口
                    if (clazz.isAssignableFrom(allClass.get(i))) {
                        if (!clazz.equals(allClass.get(i))) {
                            // 自身并不加进去
                            list.add(allClass.get(i));
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println("出现异常");
            }
        } else {
            // 如果不是接口，则获取它的所有子类
            try {
                ArrayList<Class> allClass = getAllClass(clazz.getPackage().getName());
                /**
                 * 循环判断路径下的所有类是否继承了指定类 并且排除父类自己
                 */
                for (int i = 0; i < allClass.size(); i++) {
                    if (clazz.isAssignableFrom(allClass.get(i))) {
                        if (!clazz.equals(allClass.get(i))) {
                            // 自身并不加进去
                            list.add(allClass.get(i));
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println("出现异常");
            }
        }
        return list;
    }
    /**
     * 从一个指定路径下查找所有的类
     * 
     * @param name
     */
    @SuppressWarnings("rawtypes")
    private static ArrayList<Class> getAllClass(String packagename) {
        ArrayList<Class> list = new ArrayList<>();
        // 返回对当前正在执行的线程对象的引用。
        // 返回该线程的上下文 ClassLoader。
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packagename.replace('.', '/');
        ArrayList<File> fileList = new ArrayList<>();
		/**
		 * 这里面的路径使用的是相对路径 如果大家在测试的时候获取不到，请理清目前工程所在的路径 使用相对路径更加稳定！
		 * 另外，路径中切不可包含空格、特殊字符等！
		 */
		// getResources:查找所有给定名称的资源
		// 获取jar包中的实现类:Enumeration<URL> enumeration =
		// classLoader.getResources(path);
//            Enumeration<URL> enumeration = classLoader.getSystemResources("./"+packagename);
//            while (enumeration.hasMoreElements()) {
//                URL url = enumeration.nextElement();
//                // 获取此 URL 的文件名
//                fileList.add(new File(url.getFile()));
//            }
		URL url = classLoader.getResource("./"+packagename.replace('.', '/'));
		fileList.add(new File(url.getFile()));
		for (int i = 0; i < fileList.size(); i++) {
		    list.addAll(findClass(fileList.get(i), packagename));
		}
        return list;
    }

    /**
     * 如果file是文件夹，则递归调用findClass方法，或者文件夹下的类 如果file本身是类文件，则加入list中进行保存，并返回
     * 
     * @param file
     * @param packagename
     * @return
     */
    @SuppressWarnings("rawtypes")
    private static ArrayList<Class> findClass(File file, String packagename) {
        ArrayList<Class> list = new ArrayList<>();
        if (!file.exists()) {
            return list;
        }
        // 返回一个抽象路径名数组，这些路径名表示此抽象路径名表示的目录中的文件。
        File[] files = file.listFiles();
        for (File file2 : files) {
        	String classforstr = "";
            if (file2.isDirectory()) {
                // assert !file2.getName().contains(".");// 添加断言用于判断
                if (!file2.getName().contains(".")) {
                	String str = "";
                	if (!packagename.isEmpty()) {
                		str = packagename + "." + file2.getName();
                	}
                	else {
                		str = file2.getName();
                	}
                    ArrayList<Class> arrayList = findClass(file2, str);
                    list.addAll(arrayList);
                }
            } else if (file2.getName().endsWith(".class")) {
                try {
                	classforstr = file2.getName().substring(0, file2.getName().length() - 6);
                	if (!packagename.isEmpty()) {
                		classforstr = packagename + '.' + classforstr;
                	}
                    list.add(Class.forName(classforstr));
                    // 保存的类文件不需要后缀.class
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }
}
